package com.engine.salary.service.impl;

import com.engine.common.util.ServiceUtil;
import com.engine.core.impl.Service;
import com.engine.salary.entity.salaryacct.bo.SalaryAcctFormulaBO;
import com.engine.salary.entity.salaryacct.param.SalaryAcctResultQueryParam;
import com.engine.salary.entity.salaryacct.po.SalaryAcctEmployeePO;
import com.engine.salary.entity.salaryacct.po.SalaryAcctRecordPO;
import com.engine.salary.entity.salaryacct.po.SalaryAcctResultPO;
import com.engine.salary.entity.salaryitem.param.SalaryItemSearchParam;
import com.engine.salary.entity.salaryitem.po.SalaryItemPO;
import com.engine.salary.entity.salarysob.bo.SalaryApprovalBO;
import com.engine.salary.entity.salarysob.dto.SalaryApprovalDTO;
import com.engine.salary.entity.salarysob.dto.SalarySobItemAggregateDTO;
import com.engine.salary.entity.salarysob.param.ApprovalRequestSaveParam;
import com.engine.salary.entity.salarysob.param.SalaryApprovalQueryParam;
import com.engine.salary.entity.salarysob.po.SalaryApprovalRulePO;
import com.engine.salary.entity.salarysob.po.SalarySobBackItemPO;
import com.engine.salary.entity.salarysob.po.SalarySobItemPO;
import com.engine.salary.entity.salarysob.po.SalarySobPO;
import com.engine.salary.enums.common.FilterEnum;
import com.engine.salary.enums.salaryitem.SalaryDataTypeEnum;
import com.engine.salary.exception.SalaryRunTimeException;
import com.engine.salary.mapper.salaryacct.SalaryAcctRecordMapper;
import com.engine.salary.mapper.salarysob.SalaryApprovalRuleMapper;
import com.engine.salary.service.*;
import com.engine.salary.sys.constant.SalarySysConstant;
import com.engine.salary.sys.entity.po.SalarySysConfPO;
import com.engine.salary.sys.service.SalarySysConfService;
import com.engine.salary.sys.service.impl.SalarySysConfServiceImpl;
import com.engine.salary.util.JsonUtil;
import com.engine.salary.util.SalaryEntityUtil;
import com.engine.salary.util.SalaryI18nUtil;
import com.engine.salary.util.db.IdGenerator;
import com.engine.salary.util.db.MapperProxyFactory;
import com.engine.salary.util.valid.ValidUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import weaver.conn.RecordSet;
import weaver.hrm.User;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Harryxzy
 * @ClassName SalaryApprovalRuleServiceImpl
 * @date 2024/04/23 17:35
 * @description
 */
public class SalaryApprovalRuleServiceImpl extends Service implements SalaryApprovalRuleService {

    private SalaryApprovalRuleMapper getSalaryApprovalRuleMapper() {
        return MapperProxyFactory.getProxy(SalaryApprovalRuleMapper.class);
    }

    private SalaryAcctRecordMapper getSalaryAcctRecordMapper() {
        return MapperProxyFactory.getProxy(SalaryAcctRecordMapper.class);
    }

    private SalaryItemService getSalaryItemService(User user) {
        return ServiceUtil.getService(SalaryItemServiceImpl.class, user);
    }

    private SalarySobItemService getSalarySobItemService(User user) {
        return ServiceUtil.getService(SalarySobItemServiceImpl.class, user);
    }

    private SalarySobService getSalarySobService(User user) {
        return ServiceUtil.getService(SalarySobServiceImpl.class, user);
    }

    private SalaryAcctRecordService getSalaryAcctRecordService(User user) {
        return ServiceUtil.getService(SalaryAcctRecordServiceImpl.class, user);
    }

    private SalarySysConfService getSalarySysConfService(User user) {
        return ServiceUtil.getService(SalarySysConfServiceImpl.class, user);
    }

    private SalaryAcctEmployeeService getSalaryAcctEmployeeService(User user) {
        return ServiceUtil.getService(SalaryAcctEmployeeServiceImpl.class, user);
    }

    private SalaryAcctResultService getSalaryAcctResultService(User user) {
        return ServiceUtil.getService(SalaryAcctResultServiceImpl.class, user);
    }

    private SalarySobBackItemService getSalarySobBackItemService(User user) {
        return ServiceUtil.getService(SalarySobBackItemServiceImpl.class, user);
    }

    @Override
    public List<SalaryApprovalRulePO> listAll() {
        return getSalaryApprovalRuleMapper().listAll();
    }

    @Override
    public SalaryApprovalRulePO getById(Long id) {
        return getSalaryApprovalRuleMapper().getById(id);
    }

    @Override
    public int insertIgnoreNull(SalaryApprovalRulePO po) {
        return getSalaryApprovalRuleMapper().insertIgnoreNull(po);
    }

    @Override
    public int update(SalaryApprovalRulePO salaryApprovalRule) {
        return getSalaryApprovalRuleMapper().update(salaryApprovalRule);
    }

    @Override
    public int updateIgnoreNull(SalaryApprovalRulePO salaryApprovalRule) {
        return getSalaryApprovalRuleMapper().updateIgnoreNull(salaryApprovalRule);
    }

    @Override
    public int delete(SalaryApprovalRulePO salaryApprovalRule) {
        return getSalaryApprovalRuleMapper().delete(salaryApprovalRule);
    }

    @Override
    public SalaryApprovalRulePO getBySalarySobId(Long salarySobId) {
        if(salarySobId == null) {
            return null;
        }
        List<SalaryApprovalRulePO> salaryApprovalRulePOS = getSalaryApprovalRuleMapper().listSome(SalaryApprovalRulePO.builder().salarySobId(salarySobId).build());
        if (CollectionUtils.isNotEmpty(salaryApprovalRulePOS) && salaryApprovalRulePOS.size() == 1) {
            return salaryApprovalRulePOS.get(0);
        }
        return null;
    }

    @Override
    public void deleteBySalarySobId(Long salarySobId) {
        if (salarySobId == null) {
            return;
        }
        getSalaryApprovalRuleMapper().deleteBySalarySobId(salarySobId);
    }

    @Override
    public SalaryApprovalDTO salaryApprovalForm(SalaryApprovalQueryParam queryParam) {
        // 查询薪资审批设置
        SalaryApprovalRulePO approvalRulePO = getBySalarySobId(queryParam.getSalarySobId());
        if (approvalRulePO == null) {
            // 没有审批设置信息，创建默认设置信息
            Date now = new Date();
            approvalRulePO = SalaryApprovalRulePO.builder()
                    .id(IdGenerator.generate())
                    .salarySobId(queryParam.getSalarySobId())
                    .openApproval(0)
                    .createTime(now)
                    .updateTime(now)
                    .creator(Long.valueOf(user.getUID()))
                    .deleteType(0)
                    .build();
            // 获取账套的薪资项目设置信息
            SalarySobItemAggregateDTO aggregateBySalarySobId = getSalarySobItemService(user).getAggregateBySalarySobId(queryParam.getSalarySobId());
            String setting = SalaryApprovalBO.sobItemAggregate2approvalGroupSetting(aggregateBySalarySobId);
            approvalRulePO.setApprovalGroupSetting(setting);
            insertIgnoreNull(approvalRulePO);
        }

        List<SalaryItemPO> salaryItemList = getSalaryItemService(user).listAll();
        return SalaryApprovalBO.convert2DTO(approvalRulePO, salaryItemList);
    }

    @Override
    public void saveSalaryApprovalForm(SalaryApprovalDTO salaryApprovalDTO) {
        SalarySobPO salarySobPO = getSalarySobService(user).getById(salaryApprovalDTO.getSalarySobId());
        if (salarySobPO == null) {
            throw new RuntimeException("薪资账套不存在");
        }
        // 删除原来的
        deleteBySalarySobId(salaryApprovalDTO.getSalarySobId());
        // 保存最新的
        Date now = new Date();
        SalaryApprovalRulePO po = SalaryApprovalRulePO.builder()
                .id(IdGenerator.generate())
                .salarySobId(salaryApprovalDTO.getSalarySobId())
                .openApproval(salaryApprovalDTO.getIsOpenApproval() ? 1 : 0)
                .approvalGroupSetting(JsonUtil.toJsonString(salaryApprovalDTO.getApprovalItemGroup()))
                .workflowUrl(salaryApprovalDTO.getApprovalWorkflowUrl())
                .createTime(now)
                .updateTime(now)
                .creator(Long.valueOf(user.getUID()))
                .deleteType(0)
                .build();
        insertIgnoreNull(po);
    }

    @Override
    public List<SalaryItemPO> listSalaryApprovalItem(SalaryItemSearchParam queryParam) {
        List<SalarySobItemPO> salarySobItemPOS = getSalarySobItemService(user).listBySalarySobId(queryParam.getSalarySobId());
        List<Long> salaryItemIds = salarySobItemPOS.stream()
                .filter(po -> !queryParam.getExcludeIds().contains(po.getSalaryItemId()))
                .map(SalarySobItemPO::getSalaryItemId)
                .collect(Collectors.toList());
        List<SalaryItemPO> salaryItemPOList = getSalaryItemService(user).listByIds(salaryItemIds);
        return salaryItemPOList;
    }

    @Override
    public SalaryApprovalDTO getApprovalInfoByRecordId(Long salaryAcctRecordId) {
        SalaryAcctRecordPO acctRecordPO = getSalaryAcctRecordService(user).getById(salaryAcctRecordId);
        if (acctRecordPO == null) {
            throw new SalaryRunTimeException("薪资核算记录不存在或已被删除");
        }
        SalaryApprovalRulePO approvalRulePO = getBySalarySobId(acctRecordPO.getSalarySobId());

        List<SalaryItemPO> salaryItemList = getSalaryItemService(user).listAll();
        SalaryApprovalDTO salaryApprovalDTO = SalaryApprovalBO.convert2DTO(approvalRulePO, salaryItemList);
        // 查询是否可以核算、编辑(默认开启)
        salaryApprovalDTO.setCanEdit(getRecordIsCanEdit(acctRecordPO));
        return salaryApprovalDTO;
    }

    public boolean getRecordIsCanEdit(SalaryAcctRecordPO acctRecordPO) {
        // 审批总开关，默认关闭
        SalarySysConfPO approvalStatus = getSalarySysConfService(user).getOneByCode(SalarySysConstant.SALARY_APPROVAL_STATUS);
        if (approvalStatus == null || approvalStatus.getConfValue().equals("0")) {
            return true;
        }
        // 查询是否可以核算、编辑(默认开启)
        SalarySysConfPO canEdit = getSalarySysConfService(user).getOneByCode(SalarySysConstant.APPROVAL_CAN_EDIT_RESULT_STATUS);
        if (canEdit == null || canEdit.getConfValue().equals("1")) {
            return true;
        } else {
            // 发起审批后不能核损，判断流程id是否存在
            if (StringUtils.isBlank(acctRecordPO.getApprovalId())) {
                return true;
            } else {
                RecordSet rs = new RecordSet();
                rs.execute("SELECT * FROM workflow_requestbase where REQUESTID =" + acctRecordPO.getApprovalId());
                return !rs.next();
            }
        }
    }

    @Override
    public void saveApprovalRequestId(ApprovalRequestSaveParam saveParam) {
        ValidUtil.doValidator(saveParam);
        // 获取核算记录信息
        SalaryAcctRecordPO salaryAcctRecordPO = getSalaryAcctRecordService(user).getById(saveParam.getSalaryAcctRecordId());
        if (salaryAcctRecordPO == null) {
            throw new SalaryRunTimeException("薪资核素记录不存在或已被删除");
        }
        salaryAcctRecordPO.setApprovalId(saveParam.getRequestId());
        getSalaryAcctRecordMapper().updateIgnoreNull(salaryAcctRecordPO);
    }

    @Override
    public void deleteBySalarySobIds(Collection<Long> ids) {
        ids.stream().forEach(this::deleteBySalarySobId);
    }

    @Override
    public List<SalaryApprovalRulePO> listBySalarySobIds(Collection<Long> salarySobIds) {
        if (CollectionUtils.isEmpty(salarySobIds)) {
            return Collections.emptyList();
        }
        return getSalaryApprovalRuleMapper().listSome(SalaryApprovalRulePO.builder().salarySobIds(salarySobIds).build());
    }

    @Override
    public Map<String, Object> sumRow(SalaryAcctResultQueryParam queryParam) {
        // 审批信息
        SalaryApprovalDTO approvalInfoByRecordId = getApprovalInfoByRecordId(queryParam.getSalaryAcctRecordId());
        List<Long> salaryItemIds = new ArrayList<>();
        for (SalaryApprovalDTO.approvalItemGroup groupDTO : approvalInfoByRecordId.getApprovalItemGroup()) {
            salaryItemIds.addAll(groupDTO.getApprovalItems().stream().map(SalaryApprovalDTO.approvalItem::getSalaryItemId).collect(Collectors.toList()));
        }

        //其他条件
        List<SalaryAcctResultQueryParam.OtherCondition> otherConditions = queryParam.getOtherConditions();
        List<SalaryAcctEmployeePO> salaryAcctEmployeePOList = new ArrayList<>();
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(otherConditions)) {
            List<Long> items = SalaryEntityUtil.properties(otherConditions, SalaryAcctResultQueryParam.OtherCondition::getItemId, Collectors.toList());
            List<SalaryAcctResultPO> list = getSalaryAcctResultService(user).listBySalaryAcctRecordIdsAndSalaryItemIds(Collections.singletonList(queryParam.getSalaryAcctRecordId()), items);
            for (int i = 0; i < otherConditions.size(); i++) {
                SalaryAcctResultQueryParam.OtherCondition otherCondition = otherConditions.get(i);
                Long itemId = otherCondition.getItemId();
                FilterEnum filter = otherCondition.getFilter();
                List<String> params = otherCondition.getParams();
                list = list.stream().filter(a -> Objects.equals(a.getSalaryItemId(), itemId)).filter(a -> filter.filter(params).test(a.getResultValue())).collect(Collectors.toList());
            }
            List<Long> salaryAcctEmpId = SalaryEntityUtil.properties(list, SalaryAcctResultPO::getSalaryAcctEmpId, Collectors.toList());
            if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(salaryAcctEmpId)) {
                queryParam.setIds(salaryAcctEmpId);
            }
        }

        // 查询薪资核算人员（分页）
        salaryAcctEmployeePOList = getSalaryAcctEmployeeService(user).listByResultQueryParam(queryParam);
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(salaryAcctEmployeePOList)) {
            return null;
        }
        // 查询薪资核算记录
        SalaryAcctRecordPO salaryAcctRecordPO = getSalaryAcctRecordService(user).getById(queryParam.getSalaryAcctRecordId());
        if (Objects.isNull(salaryAcctRecordPO)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98747, "薪资核算记录不存在或已被删除"));
        }
        // 查询薪资核算所用薪资账套的薪资项目
        List<SalarySobItemPO> salarySobItemPOS = getSalarySobItemService(user).listBySalarySobId(salaryAcctRecordPO.getSalarySobId());
        salarySobItemPOS = salarySobItemPOS.stream().filter(sobItem -> salaryItemIds.contains(sobItem.getSalaryItemId())).collect(Collectors.toList());
        Map<Long, SalarySobItemPO> salaryItemIdKeySalarySobItemPOMap = SalaryEntityUtil.convert2Map(salarySobItemPOS, SalarySobItemPO::getSalaryItemId);
        if (Objects.equals(salaryAcctRecordPO.getBackCalcStatus(), NumberUtils.INTEGER_ONE)) {
            // 是回算，获取回算项
            List<SalarySobBackItemPO> salarySobBackItemPOS = getSalarySobBackItemService(user).listBySalarySobId(salaryAcctRecordPO.getSalarySobId());
            salaryItemIds.addAll(salarySobBackItemPOS.stream().map(SalarySobBackItemPO::getSalaryItemId).collect(Collectors.toList()));
        }
        List<SalaryItemPO> salaryItemPOS = getSalaryItemService(user).listByIds(salaryItemIds);
        List<Long> itemIds = salaryItemPOS.stream().map(SalaryItemPO::getId).collect(Collectors.toList());

        // 查询薪资核算结果
        List<Long> salaryAcctEmployeeIds = SalaryEntityUtil.properties(salaryAcctEmployeePOList, SalaryAcctEmployeePO::getId, Collectors.toList());
        List<SalaryAcctResultPO> salaryAcctResultPOS = getSalaryAcctResultService(user).listByAcctEmployeeIdsAndSalaryItemIds(salaryAcctEmployeeIds, itemIds);

        Map<String, Object> map = new HashMap<>();
        Map<Long, List<SalaryAcctResultPO>> acctResultMap = SalaryEntityUtil.group2Map(salaryAcctResultPOS, SalaryAcctResultPO::getSalaryItemId);
        salaryItemPOS.stream().filter(item -> SalaryDataTypeEnum.NUMBER.getValue().equals(item.getDataType())).forEach(item -> {
            BigDecimal sum = Optional.ofNullable(acctResultMap.get(item.getId())).orElse(new ArrayList<>()).stream().map(SalaryAcctResultPO::getResultValue).filter(NumberUtils::isCreatable).map(BigDecimal::new).reduce(BigDecimal.ZERO, BigDecimal::add);
            map.put(item.getId().toString(), SalaryAcctFormulaBO.roundResultValue(sum.toString(), item, Collections.emptyList(), Collections.emptyMap(), salaryItemIdKeySalarySobItemPOMap));
        });
        return map;
    }

}
